﻿/********************************************************************************
** 作者： Mick
** 邮箱： zheng_jinfan@126.com
** 主页： http://www.zhengjinfan.cn
** 创始时间：2016-2-17
** 描述：
**      [辅助类]模拟HTTP操作
*********************************************************************************/
using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using BestEasyCMS.Framework.Extension;

namespace BestEasyCMS.Framework.Util
{
    /// <summary>
    /// [辅助类]模拟HTTP操作
    /// </summary>
    public class HttpOperater
    {

        // 获取网页的HTML内容，根据网页的charset自动判断Encoding
        public static string GetHtml(string url)
        {
            return GetHtml(url, null);
        }

        // 获取网页的HTML内容，指定Encoding
        private static string GetHtml(string url, Encoding encoding)
        {
            var buf = new WebClient().DownloadData(url);
            if (encoding != null) return encoding.GetString(buf);
            var html = Encoding.UTF8.GetString(buf);
            encoding = GetEncoding(html);
            if (encoding == null || encoding == Encoding.UTF8) return html;
            return encoding.GetString(buf);
        }

        // 根据网页的HTML内容提取网页的Encoding
        private static Encoding GetEncoding(string html)
        {
            const string pattern = @"(?i)\bcharset=(?<charset>[-a-zA-Z_0-9]+)";
            var charset = Regex.Match(html, pattern).Groups["charset"].Value;
            try
            {
                return Encoding.GetEncoding(charset);
            }
            catch (ArgumentException)
            {
                return null;
            }
        }

        // 根据网页的HTML内容提取网页的Title
        private static string GetTitle(string html)
        {
            const string pattern = @"(?si)<title(?:\s+(?:""[^""]*""|'[^']*'|[^""'>])*)?>(?<title>.*?)</title>";
            return Regex.Match(html, pattern).Groups["title"].Value.Trim();
        }

        // 打印网页的Encoding和Title
        private static void PrintEncodingAndTitle(string url)
        {
            var html = GetHtml(url);
            Console.WriteLine("[{0}] [{1}]", GetEncoding(html), GetTitle(html));
        }

        /// <summary>
        ///     发起Http请求
        /// </summary>
        /// <param name="httpRequestType">请求方式</param>
        /// <param name="url">请求地址</param>
        /// <param name="cookieInput">请求时传入的cookie</param>
        /// <param name="cookieOutput">服务器返回的cookie</param>
        /// <param name="postData">发送数据</param>
        /// <param name="encoding">字符编码</param>
        /// <returns></returns>
        public static string DoRequest(HttpRequestType httpRequestType, string url, string cookieInput,
                                       ref string cookieOutput, string postData, Encoding encoding)
        {
            string response;
            try
            {
                const string windowsUserName = "";
                const string windowsPwd = "";
                const string userAgent =
                    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36";
                const string accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                const string acceptLanguage = "zh-CN,zh;q=0.8";
                const string acceptEncoding = "gzip,deflate,sdch";
                var cookieContainer = GetCookie(url, cookieInput);

                var newUri = new Uri(url);
                var request = (HttpWebRequest)WebRequest.Create(newUri);
                request.PreAuthenticate = true;
                if (windowsUserName.Length > 0 & windowsPwd.Length > 0)
                {
                    request.Credentials = new NetworkCredential(windowsUserName.Trim(), windowsPwd.Trim());
                }
                request.Timeout = 20000;
                request.CookieContainer = cookieContainer;
                request.UserAgent = userAgent;
                request.Accept = accept;
                request.Headers["Accept-Language"] = acceptLanguage;
                request.Headers["Accept-Charset"] = acceptEncoding;
                request.Headers["Accept-Encoding"] = acceptEncoding;
                request.Referer = newUri.AbsoluteUri;
                request.Method = httpRequestType == HttpRequestType.Get ? "GET" : "POST";
                if (request.Method == "POST")
                {
                    request.ContentType = "application/x-www-form-urlencoded";
                    var bytes = Encoding.UTF8.GetBytes(postData);
                    request.ContentLength = bytes.Length;
                    using (var requestStream = request.GetRequestStream())
                    {
                        requestStream.Write(bytes, 0, bytes.Length);
                    }
                }
                using (var webResponse = (HttpWebResponse)request.GetResponse())
                {
                    response = new StreamReader(webResponse.GetResponseStream(), encoding).ReadToEnd();
                }
                var cookies = cookieContainer.GetCookies(newUri);
                cookieOutput = CookieTostr(cookies);
            }
            catch (NotSupportedException exception)
            {
                response = exception.Message;
            }
            catch (InvalidOperationException exception)
            {
                response = exception.Message;
            }
            catch (IOException exception)
            {
                response = exception.Message;
            }
            catch (Exception exception)
            {
                response = exception.Message;
            }
            return response;
        }



        /// <summary>
        /// 设置cookie域
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="cookieInput">cookie</param>
        /// <returns></returns>
        public static CookieContainer GetCookie(string url, string cookieInput)
        {
            var cookieContainer = new CookieContainer();
            var cookies = new CookieCollection();
            var cookiesArr = cookieInput.Split(';');
            foreach (var s in cookiesArr)
            {
                var keyValuePair = s.Split('=');
                if (keyValuePair.Length > 1)
                {
                    var cookie = new Cookie
                                     {
                                         Name = keyValuePair[0].Trim(),
                                         Value = keyValuePair[1].Trim(),
                                         Domain = GetDomain(url).Trim() //设置cookie域
                                     };
                    cookies.Add(cookie);
                }
            }
            cookieContainer.Add(cookies);
            return cookieContainer;
        }

        /// <summary>
        /// 通过Url取得域
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string GetDomain(string url)
        {
            var regex = new Regex("(?i)http[s]*://(?<domain>[\\w|.]*)",
                                  RegexOptions.CultureInvariant | RegexOptions.Compiled);
            return regex.Match(url).Groups["domain"].Value;
        }

        /// <summary>
        /// 将cookie转为字符串
        /// </summary>
        /// <param name="cookies"></param>
        /// <returns></returns>
        public static string CookieTostr(CookieCollection cookies)
        {
            return cookies.Cast<Cookie>()
                .Aggregate(string.Empty, (current, c) => current + (c.Name + "=" + c.Value + ";"));
        }

        /// <summary>
        /// 根据正则获取链接地址
        /// </summary>
        /// <param name="pageStr">原字符串</param>
        /// <param name="strStart">链接开始</param>
        /// <param name="strEnd">连接结束</param>
        /// <param name="pageUrl"></param>
        /// <returns>链接地址集合</returns>
        public static IList<string> GetLinkList(string pageStr, string strStart, string strEnd, string pageUrl)
        {
            IList<string> linkArray = new List<string>();
            if (pageStr != "")
            {
                var exsit = true;
                while (exsit)
                {
                    var startIndex = pageStr.IndexOf(strStart, StringComparison.Ordinal);
                    if (startIndex != -1)
                    {
                        startIndex += strStart.Length; //加上自己的长度
                        var linkExt = pageStr.Substring(startIndex);
                        var endIndex = linkExt.IndexOf(strEnd, StringComparison.Ordinal);
                        if (endIndex != -1)
                        {
                            linkArray.Add(
                                GetReallyUrl(linkExt.Substring(0, endIndex), pageUrl)
                                );
                            pageStr = linkExt.Substring(endIndex + strEnd.Length);
                        }
                        else
                        {
                            exsit = false;
                        }
                    }
                    else
                    {
                        exsit = false;
                    }
                }
            }
            return linkArray;
        }

        /// <summary>
        /// url由相对地址转绝对地址
        /// </summary>
        /// <param name="url">url</param>
        /// <param name="domain">域名</param>
        /// <returns></returns>
        public static string GetReallyUrl(string url, string domain)
        {
            if (url.ToLower().StartsWith("http://")) return url;
            var baseUri = new Uri(domain);
            var absoluteUri = new Uri(baseUri, url);
            return absoluteUri.ToString();// http://www.jiojio.cn/images/logo.png
        }

        /// <summary>
        /// 下载远程图片保存到本地
        /// </summary>
        /// <param name="url">图片地址（绝对地址）</param>
        /// <param name="saveDirec">图片保存目录（本地绝对目录地址）</param>
        /// <returns>图片名称</returns>
        public static string DownloadImage(string url, string saveDirec)
        {
            url = url.IsEmpty() ? "" : url;
            var result = string.Empty;//保存到本地的地址
            var index = url.LastIndexOf('.');
            if (index != -1)
            {
                ImageFormat format;
                var ext = url.Substring(index);
                switch (ext.ToLower())
                {
                    case ".bmp":
                        format = ImageFormat.Bmp;
                        break;
                    case ".gif":
                        format = ImageFormat.Gif;
                        break;
                    case ".icon":
                        format = ImageFormat.Icon;
                        break;
                    case ".jpeg":
                    case ".jpg":
                        format = ImageFormat.Jpeg;
                        break;
                    case ".png":
                        format = ImageFormat.Png;
                        break;
                    default:
                        return result;
                }
                var imageName = "{0}{1}".FormatWith(DateTime.Now.ToString("yyyyMMddHHmmssms"), ext);
                var wreq = WebRequest.Create(url);
                var wresp = (HttpWebResponse)wreq.GetResponse();
                var s = wresp.GetResponseStream();
                if (s != null)
                    using (var img = System.Drawing.Image.FromStream(s))
                    {
                        if (!Directory.Exists(saveDirec))//不存在目录则创建目录
                        {
                            Directory.CreateDirectory(saveDirec);
                        }
                        img.Save(saveDirec + imageName, format);   //保存 
                        //下面直接输出 
                        using (var ms = new MemoryStream())
                        {
                            img.Save(ms, ImageFormat.Gif);
                        }
                    }
                result = imageName;
            }
            return result;
        }
    }

    /// <summary>
    ///     HTTP请求方式
    /// </summary>
    public enum HttpRequestType
    {
        /// <summary>
        ///     GET
        /// </summary>
        Get = 1,

        /// <summary>
        ///     POST
        /// </summary>
        Post = 2
    }
}